package com.cellulam.framework.core.utils;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;

/**
 *
 */
public abstract class HashUtils {

    private static final Logger logger = LoggerFactory.getLogger(HashUtils.class);

    public static final String ALGO_MD5 = "MD5";
    public static final String ALGO_SHA256 = "SHA-256";
    public static final String ALGO_MAC_NAME = "HmacSHA1";

    private static final String ENCODING = "UTF-8";

    private static final char uppercaseHexs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    private static final char lowercaseHexs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**  */
    public final static String md5(String str) {
        return md5(str, true);
    }

    public final static String md5(String str, boolean isUppercase) {
        return hash(ALGO_MD5, str, isUppercase);
    }

    public static String sha256(final String str) {
        return sha256(str, true);
    }

    public static String sha256(final String str, boolean isUppercase) {
        return hash(ALGO_SHA256, str, isUppercase);
    }

    public final static String hash(String algo, String str, boolean isUppercase) {
        if (str == null) {
            return null;
        }
        if (StringUtils.isEmpty(algo) || StringUtils.isEmpty(str)) return "";
        try {
            byte[] md = digest(algo, str);
            return byte2Hex(md, isUppercase);
        } catch (Exception e) {
            logger.error("md5 error: ", e);
        }
        return null;
    }

    public final static String encryptPswd(String text) {
        return md5(text);
    }

    public static String base64(final String str) {
        if (StringUtils.isEmpty(str)) return "";
        return new String(Base64.encodeBase64(str.getBytes()));
    }

    public static String base64(final String str, final String encoding) {
        if (StringUtils.isEmpty(str)) return "";
        try {
            return new String(Base64.encodeBase64(str.getBytes(encoding)));
        } catch (UnsupportedEncodingException e) {
            logger.error("base64 error", e);
            return base64(str);
        }
    }

    public static byte[] decodeBase64(final String str) {
        if (StringUtils.isEmpty(str)) return new byte[0];
        return Base64.decodeBase64(str.getBytes());
    }

    private static byte[] digest(String algo, String str) throws Exception {
        byte[] btInput = str.getBytes();
        MessageDigest mdInst = MessageDigest.getInstance(algo);
        mdInst.update(btInput);
        return mdInst.digest();
    }

    public static String byte2Hex(byte[] md) {
        return byte2Hex(md, true);
    }

    public static String byte2Hex(byte[] md, boolean isUppercase) {
        char str[] = new char[md.length * 2];
        int k = 0;
        char[] hexsAlpha = isUppercase ? uppercaseHexs : lowercaseHexs;
        for (int i = 0; i < md.length; i++) {
            byte byte0 = md[i];
            str[k++] = hexsAlpha[byte0 >>> 4 & 0xf];
            str[k++] = hexsAlpha[byte0 & 0xf];
        }
        return new String(str);
    }


    /**
     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  密钥
     * @return
     * @throws Exception
     */
    public static byte[] hmacSha1(String encryptText, String encryptKey) {
        try {
            byte[] data = encryptKey.getBytes(ENCODING);
            // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
            SecretKey secretKey = new SecretKeySpec(data, ALGO_MAC_NAME);
            // 生成一个指定 Mac 算法 的 Mac 对象
            Mac mac = Mac.getInstance(ALGO_MAC_NAME);
            // 用给定密钥初始化 Mac 对象
            mac.init(secretKey);

            byte[] text = encryptText.getBytes(ENCODING);
            // 完成 Mac 操作
            return mac.doFinal(text);
        } catch (Exception e) {
            throw new RuntimeException("hmacSha1 error", e);
        }
    }

}
